import fs from 'fs'

import db from './db/inedx.js'
import Browser from '../../lib/puppeteer/browser.js'
import { htmlToCheerio, htmlToText } from '../../utils/crawler.js'
import { sleep, random } from '../../utils/util.js'
import { dataDir, type } from './config/index.js'

class Avd extends Browser {
  constructor() {
    super()
  }

  get db() {
    return db.projectConfig
  }

  get config() {
    return db.projectConfig.data[type]
  }

  async init() {
    this.browser = await this.launch({
      headless: true, // 无头模式
    })
  }

  // 开始任务
  async start() {
    await this.crawList()
  }

  // 爬取列表
  async crawList() {
    // 当前进度
    console.log(`当前进度:${this.config.currentPage}/${this.config.maxPage}`)

    const { browser } = this
    const page = await browser.newPage()
    const { url, currentPage, maxPage } = this.config

    await page.goto(`${url}?page=${currentPage}`, {
      waitUntil: 'networkidle2',
    })

    const html = await page.content()
    const listData = await this.getListData(html)

    const contentTask = []
    listData.map(item => {
      contentTask.push(this.crawlContent(item.url, item))
    })

    await Promise.all(contentTask)
    await page.close()

    if (currentPage < maxPage) {
      await sleep(random(5 * 1000, 10 * 1000))
      this.config.currentPage += 1
      await this.db.write()
      await this.crawList(type)
    }
  }

  // 获取列表数据
  async getListData(html) {
    const $ = htmlToCheerio(html)

    const results = []
    $('tbody tr').each(function () {
      const contentLink = $(this).find('td').eq(0).find('a')

      const item = {
        cve_id: contentLink.text().trim(),
        url: `https://avd.aliyun.com` + contentLink.attr('href'),
        name: $(this).find('td').eq(1).text().trim(),
        // type: $(this).find('td').eq(2).text().trim(), // 漏洞类型
        type: $(this).find('td').eq(2).find('.btn-outline-secondary').attr('title'), // 漏洞类型描述
        published_time: $(this).find('td').eq(3).text().trim(), // 披露时间
        // status: $(this).find('td').eq(4).text().trim(), // 状态
      }

      results.push(item)
    })

    return results
  }

  // 爬取详情
  async crawlContent(url, item) {
    // 延迟1-5秒执行
    await sleep(random(1000, 5000))

    const { browser } = this
    const page = await browser.newPage()
    await page.goto(url, {
      waitUntil: 'networkidle2',
    })
    const html = await page.content()
    const content = await this.getContent(html, item)

    fs.writeFile(`${dataDir}/${content.cve_id}.json`, JSON.stringify(content, null, 2), 'utf-8', err => {
      if (err) {
        console.error('写入文件时出错:', err)
        return
      }
    })

    await page.close()

    return content
  }

  // 获取内容
  async getContent(html, data = {}) {
    const $ = htmlToCheerio(html)

    const item = {
      warning: $('.col-sm-10').text(), // 告警提示 https://avd.aliyun.com/detail?id=AVD-2023-1669860
      alarmLevel: $('.badge').text(), // 告警等级

      score: Number($('.cvss-breakdown__score').text().trim()) || 0, // 阿里云评分

      refs: [],

      cveNo: $('.metric').eq(0).find('.metric-value').eq(0).text().trim(), // CVE编号
      utilization: $('.metric').eq(1).find('.metric-value').eq(0).text().trim(), // 利用情况
      patch: $('.metric').eq(2).find('.metric-value').eq(0).text().trim(), // 补丁情况

      // https://avd.aliyun.com/detail?id=AVD-2020-25182
      // CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
      installedversion: $('.cvss-breakdown__vector').text().trim(), // 影响版本
    }

    // 其他字段
    $('.cvss-breakdown__item').each(function () {
      const label = $(this).find('.cvss-breakdown__title').eq(0).text().trim()
      const value = $(this).find('.cvss-breakdown__desc').eq(0).text().trim()

      const key =
        {
          攻击路径: 'attackPath',
          攻击复杂度: 'attackComplexity',
          权限要求: 'permission',
          影响范围: 'scope',
          用户交互: 'interaction',
          可用性: 'usability',
          保密性: 'confidential',
          完整性: 'integrity',

          EXP成熟度: 'exp',
          补丁情况: 'patch',
          数据保密性: 'data_confidentiality',
          数据完整性: 'data_integrity',
          服务器危害: 'server_hazards',
          全网数量: 'total_network_num',
        }[label] || label

      item[key] = value
    })

    // 漏洞描述
    item.description = htmlToText($('.text-detail').eq(0).html())

    // 解决建议
    item.solution = htmlToText($('.text-detail').eq(1).html())

    // 参考链接
    $('.text-detail')
      .eq(2)
      .find('a')
      .each(function () {
        item.refs.push($(this).attr('href').trim())
      })

    // 受影响软件情况
    item.softs = []
    // https://avd.aliyun.com/detail?id=AVD-2020-25182
    $('.pb-4.pt-3.table-responsive tr').each(function () {
      const index = $(this).index()

      const html = $(this).html()

      if (index > 1) {
        const tdList = $(this).find('.bg-light')
        const yxm = []

        if ($(this).find('td').eq(4).text().trim()) {
          yxm.push(htmlToText($(this).find('td').eq(4).text().trim()))
        }

        if ($(this).find('td').eq(5).text().trim()) {
          yxm.push(htmlToText($(this).find('td').eq(5).text().trim()))
        }

        if (tdList.length) {
          item.softs.push({
            type: $(this).find('td').eq(0).text().trim(), // 类型
            factory: $(this).find('td').eq(1).text().trim(), // 厂商
            product: $(this).find('td').eq(2).text().trim(), // 产品
            version: $(this).find('td').eq(3).text().trim(), // 版本
            influence: yxm.join(','), // 影响面
          })
        }
      }
    })

    // CWE-ID
    item.cveList = []
    $('.card--sidebar tbody tr').each(function () {
      item.cveList.push({
        cweId: $(this).find('td').eq(0).text().trim(),
        cweType: $(this).find('td').eq(1).text().trim(),
      })
    })

    // 合并数据
    Object.assign(data, item)

    if (this.config.debug) console.log(`[爬虫] 内容获取成功`, data)

    return data
  }
}

const avd = new Avd()
await avd.init()
await avd.start()

export default Avd
